home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource5
/
357_01
/
cstar1.exe
/
OUT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-18
|
26KB
|
1,355 lines
/* C* high level output routines.
source: out.c
started: February 22, 1989
version:
February 22, 1989
March 8, 1989
PUBLIC DOMAIN SOFTWARE
The CSTAR program was placed in the public domain on June 15, 1991,
by its author and sole owner,
Edward K. Ream
1617 Monroe Street
Madison, WI 53711
(608) 257-0802
CSTAR may be used for any commercial or non-commercial purpose.
See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
*/
#include "cstar.h"
extern int sa_push[8];
extern int sd_push[8];
extern struct type_node * intrn_decl;
/*
Externally visible functions
*/
void out_arg (struct node * p);
void out_decl (struct type_node *t);
void out_function (struct fbody *p, unsigned long link_size,
int r_push, int do_addq);
void out_list (register struct node *p);
void out_tree (struct node * p);
/*
Internal functions
*/
static void out_init (struct iblock *ibp, char *name);
static void out_loc (register struct node *p);
static void out_rlist (void);
static void out_seg (int seg);
static void out_strs (char *name, char *s, unsigned long dim);
/*
Part I: ----- Code Generation Output Routines -----
*/
/*
Output code for segment declaration if there is a change
*/
static void
out_seg(int seg)
{
if (seg == segment) {
return;
}
segment = seg;
switch(seg) {
case S_BSS:
syssput(".bss");
break;
case S_DATA:
syssput(".data");
break;
case S_TEXT:
syssput(".text");
break;
default:
g_error(NULL, "internal: out_seg: bad segment");
}
sysnlput();
}
/*
Output or generate code for a list of definitions/declarations.
WARNING: no code generation (auto initializers) yet.
*/
void
out_decl(struct type_node *t)
{
register int class;
register char *name;
register struct st_node *id;
unsigned long size;
char buf[LONG_DIGITS];
TICK("out_decl");
if (nogen_flag) {
/* Suppress code generation and output. */
return;
}
while (t && t -> t_typtok == DELEMENT_TYPE) {
id = t -> t_parent;
if (id == NULL) {
switch (t -> t_link -> t_typtok) {
default:
t_error("internal: no decl parent");
case STRUCT_TYPE:
case UNION_TYPE:
;
}
t = t -> t_list;
continue;
}
class = id -> st_sclass;
/* CAUTION: name may be junk for register class */
name = id -> st_alias;
size = t -> t_link -> t_tsize;
switch (class) {
/* NOTE: initialized globals go into the data segment
and get set up with dc directives */
case AUTO_CLASS:
case REGISTER_CLASS:
if (id -> st_iniz) {
g_error(NULL, "register/auto init not ready yet");
}
/* FALLTHROUGH */
case FORMAL_CLASS:
case FORMREG_CLASS:
/* output explanatory comment */
syssput("*\t");
syssput(id -> st_name);
if (id -> st_offset) {
syssput(" = ");
convl2s(id -> st_offset, buf);
syssput(buf);
}
if (id -> st_misc & ST_REG) {
syssput(" = ");
syssput(arp_tab[id -> st_misc & ST_REG]);
}
sysnlput();
break;
case EXTERN_CLASS:
syssput(".globl ");
syssput(name);
sysnlput();
break;
case STATICL_CLASS:
/* output explanatory comment */
syssput("*\t");
syssput(id -> st_name);
syssput(" = ");
syssput(name);
sysnlput();
/* FALLTHROUGH */
case STATICG_CLASS:
if (id -> st_iniz) {
out_seg(S_DATA);
out_init(id -> st_iniz, name);
}
else {
out_seg(S_BSS);
syssput(name);
syssput(":\tds.b ");
convl2s(size, buf);
syssput(buf);
sysnlput();
}
break;
case GLOBAL_CLASS:
out_seg(S_DATA);
syssput(".globl ");
syssput(name);
sysnlput();
if (id -> st_iniz) {
out_init(id -> st_iniz, name);
}
else {
syssput(".comm ");
syssput(name);
syscput(',');
convl2s(size, buf);
syssput(buf);
sysnlput();
}
break;
default:
t_error("internal: out_decl: unknown class");
case CODE_CLASS:
case SCODE_CLASS:
case TAG_CLASS:
case TYPEDEF_CLASS:
;
}
t = t -> t_list;
}
}
/*
output a memory initializer, which means into the data segment
this is for statics and globals
it is of course useless for auto variables, for which the
initialization must actually generate code
t is a DELEMENT node
*/
#define LINELEN 70
static void
out_init(struct iblock *ibp, char *name)
{
register unsigned long i;
register int n, f, l;
register struct iblock *p, *q;
register unsigned char *s;
unsigned char buf[LONG_DIGITS];
TICK("out_init");
p = ibp;
#ifdef DEBUG
if (p == NULL) {
g_error(NULL, "internal: out_init: no block");
}
#endif
while(p) {
switch(p -> itype) {
case 0:
buf[0] = '$';
f = FALSE;
for (n = LINELEN + 1, i = 0; i < p -> idim; i++) {
/*
CAUTION:
if you wish for this to output in hex,
you MUST truncate the data to the
appropriate width; otherwise, a byte -1
will be output as $FFFFFFFF
*/
if (q = (struct iblock* ) p -> idata[i] . ipt) {
switch (q -> itype) {
case ISTRS_DEC:
s = (void *) q -> idata[1] . ipt;
break;
case ITAG_DEC:
s = (void *) q -> idata[0] . ipt;
break;
default:
g_error(NULL, "internal: out_init: unknown iblock type");
}
}
else {
convl2s(p -> idata [i] . icn, &buf[1]);
s = &buf[1]; /* leave off $ for decimal */
}
l = str_len(s);
if (n + l > LINELEN) {
/* essentially, issue a line */
f = FALSE;
n = 5;
if (name) {
syssput(name);
syscput(':');
if (str_len(name) >= 7) {
n += 8;
}
name = NULL;
}
else if (i) {
sysnlput();
}
switch (p -> isize) {
case 1:
syssput("\tdc.b ");
break;
case 2:
syssput("\tdc.w ");
break;
case 4:
syssput("\tdc.l ");
break;
default:
g_error(NULL, "internal: out_init: bad size");
}
}
else {
if (f) {
syscput(',');
n++;
}
}
f = TRUE;
n += l;
syssput(s);
} /* end for */
/* end block */
break;
case IBSSZB_DEC:
conul2sc(p -> idim, buf, 1);
syssput("\tds.b ");
syssput(buf);
break;
case ISTRA_DEC:
out_strs( name,
(char *) p -> idata[0] . ipt,
(unsigned long) p -> idim);
break;
default:
g_error(NULL, "internal: out_init: unknown block in series");
} /* end switch */
sysnlput();
p = p -> ilink;
} /* end while */
/* now reiterate the loop to output secondary declarators */
p = ibp;
while (p) {
if (p -> itype == 0) {
for (i = 0; i < p -> idim; i++) {
if (q = (struct iblock *)p->idata[i].ipt)
switch(q -> itype) {
case ISTRS_DEC:
out_strs( (char *) q -> idata[1] . ipt,
(char *) q -> idata[0] . ipt,
(unsigned long) q -> idim);
sysnlput();
}
}
}
p = p -> ilink;
}
}
/*
output a string-array declarator
*/
static void
out_strs(char *name, char *s, unsigned long dim)
{
register unsigned long i;
int f, n, l;
unsigned char buf[LONG_DIGITS];
f = 0;
buf[0] = '$';
for (n = LINELEN + 1, i = 0; ; i++) {
/* deal with chars one at a time */
if (n > LINELEN - 5) {
if (f & 2) {
/* close quote before initiating line */
syscput('\"');
}
if (name) {
syssput(name);
syscput(':');
name = NULL;
}
else if (i) {
sysnlput();
}
syssput("\tdc.b ");
n = 5;
}
if (s[i] >= ' ' && s[i] < 0x7f && s[i] != '\"') {
/* printable */
if (!(f & 2)) {
/* flip to printable (quote mode) */
if (f & 1) {
syscput(',');
n++;
}
syscput('\"');
f |= 2;
n++;
}
syscput(s[i]);
}
else {
if (f & 2) {
/* flip to nonprintable */
syscput('\"');
f ^= 2;
n++;
}
if (f & 1) {
syscput(',');
n++;
}
conl2h( (unsigned long) s[i], &buf[1], 1);
syssput(buf);
n += str_len(buf);
}
f |= 1; /* char out so flag comma required */
if (i + 1 >= dim) {
/* close any quote and exit */
if (f & 2) {
syscput('\"');
}
break;
}
} /* end for */
}
/* actual file output */
void
out_function(struct fbody *p, unsigned long link_size, int r_push, int do_addq)
{
char buf[LONG_DIGITS];
/* output the function header */
syssput("** function ");
syssput(p -> fname);
sysnlput();
/* output the strings and block decls */
out_decl(intrn_decl);
if (p -> fclass == CODE_CLASS) {
syssput(".globl "); /* declaration of the function name */
syssput(p -> fname);
sysnlput();
}
out_decl(p -> formals); /* definition of the formals */
out_decl(p -> locals); /* and the locals */
out_seg(S_TEXT);
syssput(p -> fname); /* label for the first instruction in the fn */
syscput(':');
sysnlput();
/* Output the entry code. */
if (link_size || p -> fml_size) {
conul2sc(link_size, buf, 1);
if (link_size < 32768L) {
syssput("\tlink a6,#-");
syssput(buf);
sysnlput();
}
else {
syssput("\tmove.l a6,-(a7)");
sysnlput();
syssput("\tmove.l a7,a6");
sysnlput();
syssput("\tsuba.l #");
syssput(buf);
syssput(",a7");
sysnlput();
}
}
/* output the register saves */
if (r_push) {
syssput("\tmovem.l\t");
out_rlist();
syssput(",-(a7)");
sysnlput();
}
if (do_addq) {
syssput("\tsubq.l #4, a7");
}
/*
Call the peep hole optimizer.
The nopeep_flag disables the peephole,
so there is no need for a before and after picture.
*/
if (!nopeep_flag) {
if (code1_flag) {
sysnlput();
syssput("* >>>>> code prior to peephole:");
sysnlput();
sysnlput();
out_list(code_head);
sysnlput();
}
peep_hole();
if (code2_flag) {
sysnlput();
syssput("* >>>>> code after peephole:");
sysnlput();
sysnlput();
/* Print function name for reference. */
syssput(p -> fname);
syscput(':');
sysnlput();
}
}
/* output the code list */
out_list(code_head);
/* output the register restores and actual exit */
if (do_addq) {
syssput("\taddq.l #4,a7");
sysnlput();
}
if (r_push) {
syssput("\tmovem.l\t");
syssput("(a7)+,");
out_rlist();
sysnlput();
}
if (link_size || p -> fml_size) {
if (link_size < 32768L) {
syssput("\tunlk a6");
sysnlput();
}
else {
syssput("\tmove.l a6,a7");
sysnlput();
syssput("\tmove.l (a7)+,a6");
sysnlput();
}
}
syssput("\trts");
sysnlput();
}
static void
out_rlist(void)
{
register int i, f;
f = FALSE;
for (i = 0; i <= 7; i++) {
if (sd_push[i]) {
if (f) {
syscput('/');
}
syssput(arp_tab[d_reg(i)]);
f = TRUE;
}
}
for (i = 0; i <= 7; i++) {
if (sa_push[i]) {
if (f) {
syscput('/');
}
syssput(arp_tab[a_reg(i)]);
f = TRUE;
}
}
}
/*
Part II: ----- Output routines to dump parse trees -----
*/
static void out_expr(struct node *p);
static void out_stat(struct node *p);
static void out_stat(struct node *p);
static void out_type(struct type_node *p);
static void out_1type(struct type_node *t, bool usexpand, bool fnexpand);
/*
Print a list of parse nodes.
See the file par.h for the definitions of these nodes.
*/
void
out_tree(struct node * p)
{
register int i;
register int type;
register struct type_node *id;
register struct node *q;
char buffer [100];
SL_DISABLE();
if (p == NULL) {
syssput("<NO CODE LIST>");
sysnlput();
return;
}
do {
switch (p -> n_type) {
case CALL_TOK:
syssput("CALL[");
out_expr(p -> n_arg1);
syssput(",");
sysnlput();
syssput("[");
out_expr(p -> n_arg2);
syssput("]]");
sysnlput();
break;
case Z_TOK:
sprintf(&buffer[0], "pseudo: %s: ", xzp_tab [p -> n_ztype]);
syssput(buffer);
out_expr(p -> n_zarg1);
sysnlput();
break;
case X_TOK:
type = p -> n_xtype;
sprintf(&buffer[0], "x_tok: %s(", xzp_tab [type]);
syssput(buffer);
if (type == X_BRA || type == X_BSR || is_bxx(type)) {
syssput("label: ");
syssput(p -> n_arg1 -> c_labsym);
}
else if (is_dbxx(type)) {
out_expr(p -> n_xarg1);
syssput(",label: ");
syssput(p -> n_arg2 -> c_labsym);
}
else if (type == X_JMP || type == X_JSR) {
if (p -> n_xarg1) {
out_expr(p -> n_xarg1);
}
if (p -> n_arg2) {
syssput("label: ");
syssput(p -> n_arg2 -> c_labsym);
}
}
else if (p -> n_xarg1) {
out_expr(p -> n_xarg1);
if (p -> n_xarg2) {
syssput(", ");
out_expr(p -> n_xarg2);
}
}
syssput(")");
sysnlput();
break;
case K_IF:
syssput("if (");
out_expr(p -> n_ibool);
syssput(")");
sysnlput();
out_stat(p -> n_ithen);
sysnlput();
if (p -> n_ielse) {
syssput("else ");
out_stat(p -> n_ielse);
sysnlput();
}
break;
case K_DO:
syssput("do ");
out_stat(p -> n_dbdy);
syssput(" while (");
out_expr(p -> n_dbool);
syssput(")");
sysnlput();
break;
case K_WHILE:
syssput("while (");
out_expr(p -> n_wbool);
syssput(")");
out_stat(p -> n_wbdy);
sysnlput();
break;
case K_FOR:
syssput("for(");
out_tree(p -> n_f1list);
syssput(";");
out_expr(p -> n_fbool);
syssput(";");
out_tree(p -> n_f2list);
syssput(") ");
out_stat(p -> n_fbdy);
sysnlput();
break;
case K_SWITCH:
syssput("switch(");
out_expr(p -> n_sval);
syssput(") ");
out_stat(p -> n_sbdy);
sysnlput();
break;
case K_BREAK:
syssput("break;");
sysnlput();
break;
case K_CONTINUE:
syssput("continue;");
sysnlput();
break;
case K_CASE:
sprintf(&buffer[0], "case %ld:", p -> n_ccon);
syssput(buffer);
sysnlput();
break;
case K_DEFAULT:
syssput("default:");
sysnlput();
break;
case K_RETURN:
syssput("return");
if (p -> n_rval) {
syssput("(");
out_expr(p -> n_rval);
syssput(")");
}
syssput(";");
sysnlput();
break;
case LABEL_TOK:
syssput("<LABEL> ");
syssput(p -> n_plab -> c_labsym);
syssput(":");
sysnlput();
break;
case K_GOTO:
syssput("goto ");
syssput(p -> n_plab -> c_labsym);
syssput(";");
sysnlput();
break;
/* uop_node and binop_node */
default:
i = p -> n_type;
if (is_op(i) || i == ID_TOK) {
out_expr(p);
sysnlput();
}
else {
sprintf(&buffer[0], "<INAPPROPRIATE NODE %d>",
p -> n_type);
syssput(buffer);
sysnlput();
}
break;
} /* end switch */
} /* end dowhile */
while ( (p = p -> n_next) != NULL);
}
/*
Print an expression.
See the file par.h for the definitions of these nodes.
*/
static void
out_expr(register struct node * p)
{
register struct st_node * id;
register int i;
char buffer [100];
TICK("out_expr");
if (p == NULL) {
syssput("<NULL>");
return;
}
switch (p -> n_type) {
case ID_TOK:
if (p -> n_cid != NULL) {
id = p -> n_cid;
if ((long)id & 1) {
sprintf(&buffer[0], "id: <%p>", id);
syssput(buffer);
}
else {
sprintf(&buffer[0], "id: %s", id -> st_name);
syssput(buffer);
}
}
else if (p -> n_reg1) {
sprintf(&buffer[0], "reg: %s", arp_tab[p -> n_reg1]);
syssput(buffer);
}
else if (p -> n_cltype != NULL) {
switch( (p -> n_cltype) -> t_typtok) {
case INT_TYPE:
i = p -> n_cltype -> t_mclass;
if (i & UNSIGNED_MOD) {
syssput("(u ");
}
else {
syssput("(s ");
}
if (i & LONG_MOD) {
syssput("long)");
}
else if (i & SHORT_MOD) {
syssput("short)");
}
else if (i & CHAR_MOD) {
syssput("char)");
}
else {
syssput("int)");
}
if (i & UNSIGNED_MOD) {
sprintf(&buffer[0], "%lu", p -> n_const);
syssput(buffer);
}
else {
sprintf(&buffer[0], "%ld", p -> n_const);
syssput(buffer);
}
break;
case SELEMENT_TYPE:
case UELEMENT_TYPE:
case DELEMENT_TYPE:
sprintf(&buffer[0], "(elt) %lu", p -> n_const);
syssput(buffer);
break;
case ARRAY_TYPE:
/* one should possibly check further */
sprintf(&buffer[0], "\"%s\"", p -> n_const);
syssput(buffer);
break;
case POINTER_TYPE:
sprintf(&buffer[0], "(pointer)%ld", p -> n_const);
syssput(buffer);
break;
default:
sprintf(&buffer[0], "%ld<unknown type>", p -> n_const);
syssput(buffer);
break;
}
}
else {
sprintf(&buffer[0], "%ld<missing type>", p -> n_const);
syssput(buffer);
}
break;
case CALL_TOK:
syssput("CALL[");
out_expr(p -> n_arg1);
syssput(",");
sysnlput();
syssput("[");
out_expr(p -> n_arg2);
syssput("]]");
break;
case CC_TOK:
sprintf(&buffer[0], "cc: %s", arp_tab [p -> n_xtype]);
syssput(buffer);
break;
case SEPARATOR_TOK:
out_expr(p -> n_car);
syssput(" @ ");
sysnlput();
out_expr(p -> n_next); /* n_next acts like n_arg2? */
break;
case K_CHAR:
case K_INT:
case K_LONG:
case K_STRUCT:
case K_UNION:
case K_TYPEDEF:
syssput("out_expr: what is this??");
sysnlput();
out_type((struct type_node *)p);
break;
case QUESTION_TOK:
/* Ternary OP. */
syssput("?:[");
out_expr(p -> n_arg1);
syssput(",");
sysnlput();
out_expr(p -> n_arg2);
syssput(",");
sysnlput();
out_expr(p -> n_arg3);
syssput("]");
break;
/* uop_node and binop_node */
default:
i = p -> n_type;
if (is_op(i)) {
syssput(ps_tok(i));
if (is_unop(i)) {
/* Unary OP. */
if (i == CAST_TOK) {
syssput("(");
out_1type(p -> n_cltype, TRUE, TRUE);
syssput(")");
}
syssput("[");
out_expr(p -> n_arg1);
syssput("]");
}
else {
/* Binary OP. */
syssput("[");
out_expr(p -> n_arg1);
syssput(",");
sysnlput();
out_expr(p -> n_arg2);
syssput("]");
}
}
else {
sprintf(&buffer[0],
"node \"%s\" (%d) doesn't belong in expression",
ps_tok(i), i);
syssput(buffer);
sysnlput();
}
} /* (end switch) */
}
/*
Print a statement list enclosed in curly braces.
*/
static void
out_stat(struct node * p)
{
syssput("{");
if (p != NULL) {
sysnlput();
out_tree(p);
}
syssput("}");
}
/*
Print a type.
*/
static void
out_type(struct type_node *t)
{
TICK("prtype");
out_1type(t, TRUE, TRUE);
sysnlput();
}
static void
out_1type(register struct type_node * t, bool usexpand, bool fnexpand)
{
int i;
char buffer [100];
for(;;) {
if (t == NULL) {
syssput("<NO TYPE>");
return;
}
/* first the primary printout */
i = t -> t_typtok;
if (t -> t_mclass & CONST_MOD) {
syssput("const ");
}
if (t -> t_mclass & VOLATILE_MOD) {
syssput("volatile ");
}
switch (i) {
case NULL_TYPE:
syssput("NULLtype");
return;
case BOOL_TYPE:
case FLOAT_TYPE:
case INT_TYPE:
case VOID_TYPE:
if (t -> t_mclass & UNSIGNED_MOD) {
syssput("unsigned ");
}
if (t -> t_mclass & CHAR_MOD) {
if (!(t -> t_mclass & UNSIGNED_MOD)) {
syssput("signed ");
}
syssput("char");
}
if (t -> t_mclass & SHORT_MOD) {
syssput("short ");
}
if (t -> t_mclass & LONG_MOD) {
syssput("long ");
}
break;
case ARRAY_TYPE:
sprintf(&buffer[0], "array [%ld] of ", t -> t_tdim);
syssput(buffer);
break;
case FUNCTION_TYPE: syssput("function"); break;
case POINTER_TYPE: syssput("pointer to "); break;
case CAST_TYPE: syssput("cast into "); break;
case STRUCT_TYPE:
sprintf(&buffer[0], "struct %p {%ld}:",
t, t -> t_tsize);
syssput(buffer);
break;
case UNION_TYPE:
sprintf(&buffer[0], "union %p {%ld}:",
t, t -> t_tsize);
syssput(buffer);
break;
case DECL_TYPE:
sprintf(&buffer[0], "DECL <%ld>:", t -> t_tsize);
syssput(buffer);
sysnlput();
break;
case DELEMENT_TYPE:
syssput("delement--");
break;
case SELEMENT_TYPE:
syssput(" selement--");
break;
case UELEMENT_TYPE:
syssput(" uelement--");
break;
default:
sprintf(&buffer[0], "out_type: unknown type %d", t -> t_typtok);
syssput(buffer);
return;
}
/* then further explanation and linkage */
switch (i) {
case DECL_TYPE:
t = t -> t_list;
break;
case FUNCTION_TYPE:
if (t -> t_list == NULL) {
syssput(" returning ");
}
else {
syssput("--");
sysnlput();
out_1type(t -> t_list, usexpand, FALSE);
sysnlput();
syssput("--which returns ");
}
t = t -> t_link;
break;
case STRUCT_TYPE:
case UNION_TYPE:
if (t -> t_list == NULL) {
syssput(" <NO LIST>");
}
else if (usexpand) {
sysnlput();
out_1type(t -> t_list, FALSE, fnexpand);
}
else {
syssput(" ...");
}
return;
case DELEMENT_TYPE:
case SELEMENT_TYPE:
case UELEMENT_TYPE:
if (t -> t_parent) {
if (t -> t_parent -> st_name) {
syssput(t -> t_parent -> st_name);
syssput(" ");
if (t -> t_parent -> st_alias) {
syssput(t -> t_parent -> st_alias);
}
}
sprintf(&buffer[0], "@%ld: ",
t -> t_parent -> st_offset);
syssput(buffer);
}
out_1type(t -> t_link, usexpand, fnexpand);
t = t -> t_list;
if (t == NULL) {
return;
}
if (t -> t_typtok != i) {
syssput("<t_list structure error>");
}
sysnlput();
break;
case ARRAY_TYPE:
case POINTER_TYPE:
t = t -> t_link;
break;
case BOOL_TYPE: syssput("bool"); return;
case VOID_TYPE: syssput("void"); return;
case INT_TYPE:
if (!(t -> t_mclass & CHAR_MOD)) {
syssput("int");
}
if (t -> t_link) {
sprintf(&buffer[0], "<<error> link=%p>",
t->t_link);
syssput(buffer);
}
return;
case FLOAT_TYPE:
syssput("float");
return;
default:
syssput("out_type: internal");
sysnlput();
return;
}
}
}
/*
Part III: ----- Output routines to dump code nodes -----
*/
/*
Go down the global code list and output code.
*/
void
out_list(register struct node *p)
{
register int type;
char buffer [40];
TICK("out_list");
for(; p; p = p -> c_next) {
type = p -> c_code;
if (is_xtok(type)) {
/* Output machine code to file. */
syscput('\t');
syssput(xzp_tab [type]);
if (p -> c_len1) {
syssput(xlentab[p -> c_len1]);
}
/* Output 0, 1 or 2 arguments. */
if (p -> c_arg1) {
syscput('\t');
out_arg(p -> c_arg1);
}
if (p -> c_arg2) {
if (!(p -> c_arg1)) {
syscput('\t');
syssput("<NULL>");
}
syscput(',');
out_arg(p -> c_arg2);
}
}
else if (is_ztok(type)) {
/* Output pseudo op to file. */
syscput('\t');
syssput(xzp_tab [type]);
}
else {
switch (type) {
case O_LITERAL:
out_arg(p);
break;
case O_LINENUM:
syssput("* ----- line ");
conv2s(p -> c_linenum, buffer);
syssput(buffer);
break;
case O_LABEL:
case O_ULABEL:
out_arg(p);
syscput(':');
break;
default:
g_error(NULL, "unknown code type");
/* Include error message in the file. */
syssput("* unknown code type: ");
conv2s(type, buffer);
syssput(buffer);
}
}
sysnlput();
}
}
/*
Output an argument, which is a label or a loc_node.
*/
void
out_arg(struct node * p)
{
char buffer [40];
struct st_node *id;
/* WARNING: the label nodes and the id nodes aren't the same kind */
TICK("out_arg");
if (p == NULL) {
return;
}
switch(p -> c_code) {
case O_LABEL:
syscput('L');
conv2s(p -> c_labnum, buffer);
syssput(buffer);
return;
case O_ULABEL:
/* Output internal label to file. */
if (p -> c_labnum) {
syscput('U');
conv2s(p -> c_labnum, buffer);
syssput(buffer);
}
else {
syssput(p -> c_labsym);
}
break;
case O_LITERAL:
syssput(p -> c_lit);
return;
case ID_TOK:
out_loc(p);
return;
default:
g_error(p, "out_arg: internal: bad node\n");
printf("bad node %p: c_code=%d %s\n",
p, p -> c_code, ps_tok(p->c_code));
}
}
/*
Output a loc node.
*/
static void
out_loc(register struct node *p)
{
char buffer[40];
register char mode;
register struct st_node *id;
mode = p -> n_mode;
if (mode == VALUE_MODE) {
if (!p -> n_reg1) {
syscput('#');
}
}
if (id = p -> n_cid) {
syssput(id -> st_alias);
}
if (p -> n_const || (!p -> n_cid &&
((p -> n_reg1 && p -> n_reg2) || (!p -> n_reg1 && !p -> n_reg2)) ) ) {
if (p -> n_cid && p -> n_const >= 0) {
syscput('+');
}
convl2s(p -> n_const, buffer);
syssput(buffer);
}
if (mode && p -> n_reg1) {
if (mode == EAPRD_MODE) {
syscput('-');
}
syscput('(');
}
if (p -> n_reg1) {
syssput(arp_tab [p -> n_reg1]);
if (p -> n_reg2) {
syscput(',');
syssput(arp_tab [p -> n_reg2]);
switch (p -> n_scflag) {
case X2_WORD:
syssput(".w");
break;
case X2_LONG:
syssput(".l");
break;
default:
g_error(p, "out_loc: internal: unscaled reg2\n");
break;
case 0:
case X2_OK:
;
}
}
}
if (mode && p -> n_reg1) {
syscput(')');
if (mode == EAPSI_MODE) {
syscput('+');
}
}
}
char *
ps_tok(int tok)
{
if (tok > 0 && tok <= LABEL_TOK) {
return kp_tab[tok];
}
else {
return "<bad TOKEN>";
}
}